package com.example.chat.ws;

import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.http.HttpSession;
import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import org.springframework.stereotype.Component;

import com.alibaba.fastjson2.JSON;
import com.example.chat.config.GetHttpSessionConfigurator;
import com.example.chat.utils.MessageUtils;
import com.example.chat.vo.Message;

import lombok.extern.slf4j.Slf4j;

/**
 * 处理具体websocket消息的接口
 * @author Lay.He
 * @date 2023/11/23 21:19
 */
@Slf4j
@ServerEndpoint(value = "/chat",configurator = GetHttpSessionConfigurator.class)
@Component
public class ChatEndpoint {

    private static final Map<String,Session> onlineUsers = new ConcurrentHashMap<>();

    private HttpSession httpSession;
    /**
     * 连接建立时被调用
     * @param session Session
     * @param config EndpointConfig
     */
    @OnOpen
    public void onOpen(Session session, EndpointConfig config){
        //获取httpSession并赋值，便于后面OnMessage（）和OnClose（）时使用
        this.httpSession = (HttpSession)config.getUserProperties()
            .get(HttpSession.class.getName());
        String user = (String)httpSession.getAttribute("user");
        //1、 将session进行保存
        onlineUsers.put(user,session);
        log.info("用户【{}】已上线",user);

        //2、广播消息，需要将登录的所有用户推送给其他所有用户
        String message = MessageUtils.getMessage(true, null, getFriends());
        broadcastAllUsers(message);
    }

    private Set<String> getFriends(){
        return  onlineUsers.keySet();
    }

    /**
     * 广播消息，推送给其他所有用户
     * @param message 消息
     */
    private void broadcastAllUsers(String message){
        String user = (String)httpSession.getAttribute("user");
        log.info("当前用户【{}】，广播消息给其他所有用户消息：【{}】",user,message);

        Set<Map.Entry<String, Session>> entries = onlineUsers.entrySet();
        for (Map.Entry<String, Session> entry : entries) {
            Session session = entry.getValue();
            //发送消息
            try {
                session.getBasicRemote().sendText(message);
            } catch (IOException e) {
                // e.printStackTrace();
                //记录日志
                log.info("当前用户【{}】，广播消息失败，失败原因为：【{}】",user,e.getMessage());
            }
        }
    }

    /**
     * 浏览器发送消息到服务端，接收到客户端发送的数据时该方法被调用
     * @param message 消息 数据格式: {"toName":"张三","message":"你好..."}
     */
    @OnMessage
    public void onMessage(String message){
        //将消息推送给指定的用户
        Message msg = JSON.parseObject(message, Message.class);
        //获取指定用户的用户名
        String toName = msg.getToName();
        //获取发送的消息
        String sendMsg = msg.getMessage();
        //获取当前用户的用户名
        String currentUser = (String)httpSession.getAttribute("user");
        String msgStr = MessageUtils.getMessage(false, currentUser, sendMsg);

        Session session = onlineUsers.get(toName);
        try {
            session.getBasicRemote()
                 .sendText(msgStr);
            log.info("当前用户【{}】,给指定用户【{}】,发送了消息:【{}】",currentUser,toName,sendMsg);
        } catch (IOException e) {
            // e.printStackTrace();
            //记录日志
            log.info("当前用户【{}】,给指定用户【{}】,发送了消息失败，失败原因:【{}】",currentUser,toName,e.getMessage());
        }
    }

    /**
     * 连接关闭时被调用
     * @param session Session
     */
    @OnClose
    public void onClose(Session session){
        //1、 从 onlineUsers 中删除当前用户的session对象
        String user = (String)httpSession.getAttribute("user");
        onlineUsers.remove(user);
        log.info("用户【{}】已下线",user);

        //2、通知其他所有的用户，当前用户下线了。
        String message = MessageUtils.getMessage(true, null, getFriends());
        broadcastAllUsers(message);
    }
}
